﻿namespace FileCategorizerTest
{
    using System;
    using System.IO;
    using FileCategorizer.Engine;
    using FileCategorizer.Engine.Data;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// This is a test suite for the monitor.
    /// </summary>
    [TestClass]
    public class MonitorTest
    {
        /// <summary>
        /// A global instance of the monitor for all tests to share.
        /// </summary>
        private static Monitor monitor;

        /// <summary>
        /// The testing directory.
        /// </summary>
        private static string testDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

        /// <summary>
        /// ClassInitialize runs before running the first test in the class
        /// </summary>
        /// <param name="testContext">The current test context.</param>
        [ClassInitialize()]
        public static void MonitorTestInitialize(TestContext testContext)
        {
            if (monitor == null)
            {
                monitor = new Monitor(DatabaseFactory.Instance);
            }
        }

        /// <summary>
        /// ClassCleanup runs after all tests in a class have run
        /// </summary>
        [ClassCleanup()]
        public static void MonitorTestCleanup()
        {
            monitor = null;
        }

        /// <summary>
        /// Tests the monitor's ability to have a directory assigned to its
        /// watch list.
        /// </summary>
        [TestMethod]
        public void AddDirectoryToMonitorTest()
        {
            monitor.Reset();
            Assert.AreEqual(0, monitor.Count);
            monitor.Add(testDir);
            Assert.IsTrue(monitor.Contains(testDir));
            Assert.AreEqual(1, monitor.Count);
        }

        /// <summary>
        /// Provides the monitor with an invalid directory to ensure
        /// the system rejects non-directory arguments.
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(FileNotFoundException))]
        public void AddInvalidDirectory()
        {
            string path = Path.Combine(testDir, "ttkald");
            monitor.Add(path);
        }

        /// <summary>
        /// Provides the monitor with a file name instead of a path to
        /// monitor.
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(FileNotFoundException))]
        public void AddFileToDirectoryWatcher()
        {
            string path = Path.Combine(testDir, "temp.txt");
            using (File.CreateText(path))
            {
                monitor.Add(path);
            }

            File.Delete(path);
            Assert.IsFalse(File.Exists(path));
        }

        /// <summary>
        /// Attempts to remove a directory from the watcher which isn't
        /// currently assigned.
        /// </summary>
        [TestMethod]
        public void RemoveNonMappedDirectory()
        {
            monitor.Remove(@"C:\");
        }

        /// <summary>
        /// Tests the monitor's ability to remove a directory from its watch
        /// list.
        /// </summary>
        [TestMethod]
        public void RemoveDirectoryFromMonitorTest()
        {
            monitor.Reset();
            Assert.AreEqual(0, monitor.Count);

            monitor.Add(testDir);
            Assert.IsTrue(monitor.Contains(testDir));
            Assert.AreEqual(1, monitor.Count);

            monitor.Remove(testDir);
            Assert.IsFalse(monitor.Contains(testDir));
            Assert.AreEqual(0, monitor.Count);
        }

        /// <summary>
        /// This test adds a new file to a monitored directory, then verifies
        /// the file is placed in the categorization queue.
        /// </summary>
        [TestMethod]
        public void DetectNewFileTest()
        {
            string filePath = Path.Combine(testDir, "temp.txt");

            monitor.Add(testDir);

            // test file
            StreamWriter w = File.CreateText(filePath);
            w.WriteLine();
            w.Close();

            try
            {
                Assert.IsTrue(monitor.HasQueuedFiles);
                Assert.AreEqual(filePath, monitor.QueuedFiles.Dequeue());
            }
            finally
            {
                // remove the test file
                File.Delete(filePath);
                Assert.IsFalse(File.Exists(filePath));  // make sure we cleaned up
            }
        }

        /// <summary>
        /// This test removes a file from a monitored directory, then verifies
        /// the file's data was completely removed from the database.
        /// </summary>
        [TestMethod]
        public void DetectDeletedFileTest()
        { 
        }
    }
}